/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_Studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#pragma once

#include <mutex>
#include <set>
//#include <stack>

#include <基本类型.h>
#include <S_键值序列容器.h>

#include <core/文件块.h>
#include "节点.h"
#include "编译声明代码.h"

//typedef bool(*f_JIT_接口函数指针2)(E_JIT_FunParam* 参数, uint8 参数数量, E_JIT_FunParam* 静态参数, uint8 静态参数数量);
typedef bool(*f_JIT_接口函数指针_class)(void* self, E_JIT_FunParam* 参数, uint8 参数数量);
typedef void(*f_JIT_接口函数指针初始化)(E_JIT_FunParam* 参数);

typedef C_节点基类*(*fp_创建节点函数)(S_设备环境& ctx, class C_节点树* 子节点树);


struct S_Scene;
struct S_物理解算器;


enum E_节点树更新方式 {
	e_手动更新,
	e_帧更新,
	e_实时更新
};

typedef enum : uint16 {
	e_type_物体节点树 = 1,
	e_type_材质节点树 = 1 << 1,
	e_type_渲染节点树 = 1 << 2,
	e_type_几何节点树 = 1 << 3,
	e_type_着色节点树 = 1 << 4,
	e_type_函数节点树 = 1 << 5,
	e_type_循环节点树 = 1 << 6,
	e_type_并行节点树 = 1 << 7,
	
	e_type_包节点树   = 1 << 8,
	e_type_模块节点树 = 1 << 9,
	e_type_UI节点树   = 1 << 10,
	e_type_纹理节点树 = 1 << 11,
}E_节点树类型;

typedef enum : uint64 {
	//e_节点编译_外部调用 = DEF_字符串拼接ID('e', 'x', 'p', 'o', 'r', 't', '\0', '\0', '\0'),
	//e_节点编译_内联调用 = DEF_字符串拼接ID('i', 'n', 'l', 'i', 'n', 'e', '\0', '\0', '\0'),
	e_节点编译_重新编译 = 0,
	e_节点编译_外部调用 = 1 << 0,
	e_节点编译_内联调用 = 1 << 1,
	e_节点编译_完成 = e_节点编译_外部调用 | e_节点编译_内联调用,
}E_节点树编译位标志;



struct S_节点链接线记录 {
	struct S_节点链接线链接到输出插座记录 {
		std::wstring	m_链接到的输出插座所在节点;
		int16			m_链接到的输出插座ID;
	};

	std::wstring	m_当前节点名称;
	uint32			m_当前节点输入插座ID;

	std::vector<S_节点链接线链接到输出插座记录> m_链接到输出插座;
};


struct S_节点组 {
	std::vector<C_节点基类*> m_组;
	std::wstring             m_Name;
	uint32                   m_Type;
};


class C_节点树 {
	S_Scene*			m_当前场景;
	E_节点树更新方式	m_更新方式;
	C_节点基类*			m_父节点;
	

protected:
	bool				m_开启标记循环内部节点;
	uint32				m_JIT参数ID;

public:
	C_节点树(const std::wstring&  idName);
	~C_节点树();

	std::set<C_节点基类*>		m_Nodes;
	std::wstring				m_IDName;
	uint32						m_ID;
	E_节点树类型				m_树类型;
	

	std::mutex								m_节点更新锁;
	std::vector<std::vector<C_节点基类*>>	m_层更新节点;
	std::vector<C_节点基类*>				m_开始节点;
	uint32									m_中断层;

	//std::vector<S_节点组*>					m_节点组;


	//vec2		m_中心;
	//vec2		m_边界;
	static C_StrKey分配器    g_函数名称分配;
	static C_StrKey分配器    G节点名称分配;
	static uint8             G_编译优化;
	static std::mutex	     g_分配内存锁;
	//static std::vector<E_JIT_FunParam>		G节点JIT参数;
	static std::vector<void**> g_节点JIT参数;
	static std::vector<uint32> g_JIT一级参数删除记录;


	//std::vector<void*> m_节点JIT参数;
	std::vector<void*> m_JIT二级参数;
	uint32             m_参数全局偏移;


	std::mutex      m_编译状态锁;
	uint64          m_以编译;


	static bool	g_节点是否可编辑;
	bool		m_节点结构改变;
	bool		m_开启帧更新;
	
	bool		m_未保存或加载;
	bool		m_以删除;
	uint64		m_程序集;
	bool		m_开始编译;
	bool		m_编译以准备好;
	//E_JIT方式	m_编译方式;
	//std::string m_Code;
	std::set<C_节点基类*> m_节点树绑定的父节点;

	static C_节点树* f_get节点树(const std::wstring& key);

	void		     f_set父节点(C_节点基类* node) { 
		m_父节点 = node; 
	}
	C_节点基类*	f_get父节点() { return m_父节点; }
	
	std::string f_getName();



	S_Props		m_函数名称;
	S_Props		m_外部加载;
	S_Props		m_代码文件路径;
	S_Props		m_编译方式;
	
	std::string m_Code;
	std::string m_ReleaseCode;
	E_方向      m_布局方向;
	


	void		f_准备Update();
	void		f_标记区域节点(C_节点基类* node);
	bool		f_Update(uint32 层ID);
	std::string	f_编译一层节点(uint32 层ID, std::string& 声明, std::vector<std::string>& 定义, std::string& 释放);
	//static uint16		f_genJIT参数ID();
	uint32		f_gen参数ID();
	void		f_准备编译节点树();
	
	void		f_添加节点(C_节点基类* node);
	void		f_删除节点(C_节点基类* node);

	uint32		f_getNodeNum();

	C_节点基类*		f_getNode(const std::string& key);
	//S_物理解算器*	f_get物理引擎();

	void		f_重置节点更新时间();
	void		f_重置节点名称();
	void		f_reset();
	
	C_节点树*	f_拷贝();
	C_节点树*	f_getThisTree();

protected:
	void		f_查找开始节点();
	void		f_准备帧Update();
	//void	f_取首节点是否要更新(vector<bool>& start);
	//void	f_帧更新节点标记为已更新();
	
	void	f_计算节点层级();
	void	f_推进节点层级计算(std::vector<C_节点基类*>& nodes, uint32 depth);
	//void	f_节点更新_释放上一层数据();

private:



};








inline C_节点树* f_getTree(const std::wstring& treeName) {
	C_节点树* tree = C_节点树::f_get节点树(treeName);

	if (!tree) {
		tree = new C_节点树(treeName);
	}

	return tree;
}






C_节点树* f_node_Create节点树(bool isRootNode, std::wstring name = L"物体");
C_节点树* f_node_Create包节点树(bool isRootNode, std::wstring name = L"包");
C_节点树* f_node_Create渲染节点树(bool isRootNode, std::wstring name = L"渲染");
C_节点树* f_node_Create几何节点树(bool isRootNode, std::wstring name = L"geom_");
C_节点树* f_node_Create函数节点树(bool isRootNode, std::wstring name = L"函数");
C_节点树* f_node_Create循环节点树(bool isRootNode, std::wstring name = L"循环");
C_节点树* f_node_Create材质节点树(bool isRootNode, std::wstring name = L"材质");
C_节点树* f_node_Create着色节点树(bool isRootNode, std::wstring name = L"着色");
C_节点树* f_node_Create纹理节点树(bool isRootNode, std::wstring name = L"纹理");

void	f_NT_销毁节点(C_节点树* t);
void	f_NT_Release(C_节点树* t);
//C_节点树* f_node_加载节点树(FILE* f);
//void f_node_保存节点树(C_节点树& trees, FILE* f);

void f_node_帧更新(bool t);
bool f_node_帧是否更新();



//void f_NT_准备帧更新节点(C_节点树* tree);
void f_NT_刷新全局参数(C_节点树* tree);
void f_NT_冻结节点(C_节点基类* rn, bool 冻结);
void f_NT_预处理冻结节点(C_节点树* tree);
bool f_NT_StepUpdate节点(C_节点树* tree, bool 帧更新);
bool f_NT_编译节点(C_节点基类* rn, std::string path, bool 编译成动态链接库 = false);

std::string f_NT_编译节点树(C_节点树* tree, std::vector<std::string>& 定义, std::string& 声明);
uint64      f_NT_初始化函数接口(uint64 程序集, std::string 函数名称, E_JIT方式 方式 = E_JIT方式::e_jit_llvm);
bool        f_NT_是否内联调用(C_节点基类* node);

uint8* f_NT_序列化节点组数据(C_节点树* tree, S_文件块& 文件块);
void f_NT_读取节点组数据(C_节点树* tree);
void f_NT_保存节点组数据(C_节点树* tree);

void f_NT_构建框节点依赖结构(C_节点基类* 当前框节点, std::vector<C_节点基类*>& 框包含节点, std::map<std::wstring, C_节点基类*>& 新节点集);


std::string f_代码构建_属性变量(S_Props& prop, C_节点树* rt);
std::string f_代码构建_变量(C_节点树* rt, void* data, E_值类型 type);
std::string f_代码构建_插座变量数组数量(C_插座基类& socket, std::string& name, int32 loc = 0);

Inline std::string f_代码构建_节点树输出变量名称(C_节点树* rt, uint32 id) {
	return rt->f_getName() + "输出参数" + f_整数值转字符串(id);
}
Inline std::string f_代码构建_节点树输出变量名称(C_节点基类* rn, uint32 id) {
	return rn->f_getName() + "输出参数" + f_整数值转字符串(id);
}

Inline bool f_代码构建_数组指针(C_插座基类* socket) {
	return f_代码构建_是否为数组(socket->m_Type);
}

Inline std::string f_代码构建_节点树输入输出变量引用(E_值类型 type, uint32 id) {
	std::string 参数名称;

	if (f_代码构建_是否为数组(type)) {
		参数名称 = "((" + f_node_getDataTypeName(type) + "*)(inData[" + f_整数值转字符串(id) + "]))";
	}
	else {
		参数名称 = "*((" + f_node_getDataTypeName(type) + "*)(inData[" + f_整数值转字符串(id) + "]))";
	}
	//switch (socket->m_Type) {
	//	case E_值类型::e_Type_Mesh:
	//	case E_值类型::e_Type_Mesh_1D:
	//	case E_值类型::e_Type_多边形元素:
	//	case E_值类型::e_Type_多边形元素1D:
	//	case E_值类型::e_Type_多边形面:
	//	case E_值类型::e_Type_Bool_1D:
	//	case E_值类型::e_Type_Vec2_1D:
	//	case E_值类型::e_Type_Vec3_1D:
	//	case E_值类型::e_Type_Vec4_1D:
	//	case E_值类型::e_Type_Mat4X4_1D:
	//	case E_值类型::e_Type_UI32_1D:
	//	case E_值类型::e_Type_I8_1D:
	//	case E_值类型::e_Type_I32_1D:
	//	case E_值类型::e_Type_UI32_2D:
	//	case E_值类型::e_Type_F32_1D: 参数名称 = "((" + f_node_getDataTypeName(socket->m_Type) + "*)(inData[" + f_整数值转字符串(id) + "]))"; break;
	//	default: 参数名称 = "*((" + f_node_getDataTypeName(socket->m_Type) + "*)(inData[" + f_整数值转字符串(id) + "]))";
	//}
	return 参数名称;
}

void f_代码构建_输入输出节点参数(C_节点基类* rn, std::vector<C_节点基类*>& m_InNodes, const std::vector<C_节点基类*>& m_OutNudes);



void f_构建代码_分配渲染器GPU属性变量(S_Props& prop);
void f_构建代码_释放渲染器GPU属性变量(S_Props& prop);
void f_构建代码_分配渲染器GPU插座变量(C_插座基类& socket);
void f_构建代码_释放渲染器GPU插座变量(C_插座基类& socket);


